<HEAD>
  <SCRIPT SRC="../ganja.js"></SCRIPT>
</HEAD>
<BODY><SCRIPT>
// Create a Clifford Algebra with 3,0,1 metric. 
Algebra(3,0,1,()=>{ 

  // Specify a point directly (trivectors specified with overloaded e-notation.)
  var point = (x,y,z)=>1e123-x*1e012-y*1e013+z*1e023;
  var rotor = (P,a)=>Math.cos(a/2)+Math.sin(a/2)*P.Normalized;
  
  // Load a wavefront 3D OBJ file.
  var obj = (url,complete)=>{
    var req = new XMLHttpRequest(); req.onload=e=>{
      var t = req.response.split('\n'), v=t.filter(x=>x.match(/^v /i)), f=t.filter(x=>x.match(/^f /i)).map(x=>x.split(/\s+/).slice(1,4).map(x=>parseInt(x))), p;
      complete(p=v.map(x=>point.apply(this,x.split(/\s+/).slice(1).map(x=>13*parseFloat(x)))),                                                // points
               [].concat.apply([],f.map(x=>x.map((y,yi)=>(y>x[(yi+1)%3])?undefined:[y,x[(yi+1)%3]]))).filter(x=>x).map(x=>x.map(x=>p[x-1])),  // edges
               f.map(x=>x.map(x=>p[x-1])));                                                                                                   // faces
    }; req.open("GET",url,false); req.send();
  }
  
  // Our camera position and orientation
  var  time=0, camera=(1-1e02+1e13-1.2e03+0.9e01).Normalized, cut=-0.57*1.3e0+1e2, mini=camera*(1-1.3e03+3e02-5.5e01)*rotor(1e12,Math.PI/2);
    
  // Read obj
  obj("bunny.obj",(points,edges,faces)=>{
      // Store the bunny as a rigid body - this optimizes the GL path.
      var bunny={data:faces};
      
      // Precalculate face and edge bivectors.
      var facedata = faces.map(x=>{ var f; return [f=x[0]&x[1]&x[2],(f<<(x[0]&x[1])),(f<<(x[1]&x[2])),(f<<(x[2]&x[0]))]});
      
      // Now graph (animated) the cut .. 
      document.body.appendChild(this.graph(()=>{
        // Animate cutting plane and camera
        var time=performance.now()/25000;    
        cut.set( (1.43+ Math.sin(time*3))*1e0+1e2);
        camera.set( ((1-1e03-.75e02)* (Math.cos(time*5)+Math.sin(time*5)*1e13)).Normalized )
        
        // recalculate the contour. (cuts of all polies with cutting plane)
        var contour=[], minicontour=[]; faces.forEach((x,i)=>{
            var [f,e1,e2,e3]=facedata[i], l=(f^cut),
                p1=(l^e1),p2=(l^e2),p3=(l^e3),
                p12=(p1&e2).s>=0,p13=(p1&e3).s>=0,p23=(p2&e3).s<0, res=[];
            if (p1.e123 && (p12 == p13)) res.push(p1);
            if (p2.e123 && (p12 == p23)) res.push(p2);
            if (p3.e123 && (p13 != p23)) res.push(p3);
            if (res.length==2) { contour.push(res); minicontour.push(res.map(x=>(camera**-1*mini).Normalized>>>x)) };
        })
        
        return [0x664422,bunny,0xffffff,...contour,0x000000,...minicontour];
      },{animate:true,gl:true,camera}));
  });
});
</SCRIPT></BODY>